﻿using System;
using System.Collections.Generic;
using System.Text;

namespace InSilicio.Spatial
{
    /// <summary>
    /// A class representing an adaptive octree.
    /// Used for hierarchical acceleration.
    /// </summary>
    public class Octree
    {
        #region Variables
        /// <summary>
        /// The root node of the octree.
        /// </summary>
        protected Octant rootOctant;
        /// <summary>
        /// The maximum depth the tree is allowed to reach.  Overrides the triangle limit if there are conflicts.
        /// </summary>
        protected int maxDepth;
        /// <summary>
        /// The bounds of the entire octree.
        /// </summary>
        protected AABB octreeBounds;
        /// <summary>
        /// The ratio required for an octant to, when subdivided, be subdivided into eight parts.
        /// If this ratio is not met, the octant will only be subdivided in one or two dimensions.
        /// </summary>
        protected float cubeThreshold;
        /// <summary>
        /// The maximum number of triangles an octant can have before being subdivided.
        /// This limit can be surpassed if the tree is already at its maximum depth.
        /// </summary>
        protected int triangleLimit;
        #endregion

        #region Properties
        /// <summary>
        /// Gets the maximum depth of the tree.  
        /// </summary>
        public int MaxDepth
        {
            get { return maxDepth; }
        }
        /// <summary>
        /// Gets the axis-aligned bounding box of the octree.
        /// </summary>
        public AABB Bounds
        {
            get { return octreeBounds; }
        }
        /// <summary>
        /// Gets the cube threshold for the tree.  
        /// </summary>
        public float CubeThreshold
        {
            get { return cubeThreshold; }
        }
        /// <summary>
        /// Gets the triangle limit for each octant.  
        /// </summary>
        public int TriangleLimit
        {
            get { return triangleLimit; }
        }
        #endregion

        /// <summary>
        /// Constructs an octree with the specified parameters.
        /// </summary>
        /// <param name="triangleLimit">The maximum number of triangles an octant can have before being subdivided.</param>
        /// <param name="maxDepth">The maximum depth the tree is allowed to reach.</param>
        /// <param name="octreeBounds">The bounds that this octree encompasses.</param>
        /// <param name="cubeThreshold">The threshold for something being "cube enough" to subdivide in all three dimensions.</param>
        public Octree(int triangleLimit, int maxDepth, AABB octreeBounds, float cubeThreshold)
        {
            this.triangleLimit = (triangleLimit > 10 ? triangleLimit : 10);
            this.maxDepth = (maxDepth > 0 ? maxDepth : 1);
            this.octreeBounds = octreeBounds ?? new AABB();
            this.cubeThreshold = (cubeThreshold > 0 && cubeThreshold < 0.55) ? cubeThreshold : 0.4f;
            this.rootOctant = new Octant(octreeBounds);
        }

        /// <summary>
        /// Removes leaves in the octree that are completely invisible to the camera, based on 
        /// its current viewing direction and field of view.  Should only be called after the 
        /// entire octree has been built.
        /// </summary>
        /// <param name="cam">The camera to be used to cull away unneeded parts of the scene.</param>
        public void CullToCameraView(Camera cam)
        {

        }


    }
}
